那麼最一開始學一個程式語言的起手式想必不用我多說吧。
「Hello World!」
fn hello() {
println!("Hello World!");
}
那你可能想說,為什麼不是 main function
因為我 source code 放在 Github 上阿。
我打算把它區分清楚這樣查閱的時候也比較方便 owo 。
Github連結
希望有人幫我按星星 owo/
那接下來就是基本的介紹。
Rust 的函數寫法就是
fn function_name(/*引入*/){
//code
}
那中間就是撰寫 code 的主要位置。
但是如果說是稍微有程式觀念的就會知道我少講了一個東西。
「回傳值格式」
在 Rust 裡回傳值的設定方法就是
fn function_name(/*引入*/) -> /*回傳值形式*/{
/*code*/
}
回傳方式有兩種
2.可能看起來比較複雜,直接看 code 吧
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
// 回傳 a + b
pub fn add(a: i32, b: i32) -> i32 {
a + b
a += b;
}
// 不合法
pub fn add(a: i32, b: i32) -> i32 {
return a + b;
a += b;
}
// 但是可以這樣寫
要注意的是函數也可以作為引數傳入函數中,有點繞口令,還是看 Code 啦
fn into(op: fn(i8, i8) -> i8, a: i8, b: i8) -> i8 {
op(a, b)
}
fn add(a: i8, b: i8) -> i8 {
a + b
}
fn product(a: i8, b: i8) -> i8 {
a * b
}
pub fn oao() {
let a = 5;
let b = 4;
println!("{}", into(add, a, b));
println!("{}", into(product, a, b));
}
那可能有些人,會特別在意速度,那其實 Rust 也有 CTFE (Compile Time Function Evaluation)
也就是編譯期處理,把原本要運行的東西拉入編譯中處理。
我自己是在學 Rust 前不知道這個東西,所以不確定其他語言有沒有
寫法如下
pub const fn CTFE() -> i8 {
5
}
就前面加一個 const 即可,我自己測試 Stable 版本中已經可用了
pub fn owo(){
println!("1");
}
pub fn func() {
owo();
{
owo();
fn owo(){
println!("2");
}
}
}
具體輸出為
那可以發現說 他的函數會先吃同樣的範圍的。
而不會吃外面的,但是我也不會這樣寫。
可讀性有夠差 感覺混淆程式碼很好用
在 Rust 中可以一次回傳多項。
就像是
pub fn retmany() -> (i32, i32) {
(5, 8)
}
這樣的話其實他的回傳值就有兩個,但是相對的,也要靠兩個變數去接
就像是這樣
pub fn return_many() {
let (a, b) = function::retmany();
println!("{} {}", a, b);
}
就能接到 a 跟 b 兩個值
如果這樣寫
pub fn uninput(_: i32) {
println!("{}", _);
}
並使用,會報錯
error: in expressions, `_` can only be used on the left-hand side of an assignment
--> src/Basic/function.rs:21:20
|
21 | println!("{}", _);
| ^ `_` not allowed here
也就是可以讓傳入的東西不能用,應該在後面的 Bevy Engine 會用到。
先解釋一下泛型函數的使用用途。
今天如果說,要寫一個能使用多型別 Ex: float, Int 的程式,
那可能你就要重複寫兩個函數,差別只有一個是 Float 型式的一個是 Int 型式的
為了解決這種東西,泛型函數誕生了,而以下的使用方法我是以官方 Rust Book 的文檔來寫
因為我想不到該怎麼解釋 QwQ
pub fn Tfunc<T>(a: &[T]) {
}
以上的代碼就是泛型的使用方式,那只要這樣就能傳入不同型式了。
但是,有時後會遇到問題。
pub fn Tfunc<T>(a: &[T]) -> T {
let mut largest = a[0];
for &i in a.iter() {
if i < largest {
largest = i;
}
}
largest
}
假如說這樣編譯的話,會出現
這樣的錯誤,主要是由於使用了 "<" 所導致的
這是由於如果要做大於小於的判斷,必須要實做
PartialOrd 特性,但是因為使用了泛型,所以這個型別不一定會使用此特性,
故需要讓傳入的 T 有這個特性
pub fn Tfunc<T: PartialOrd>(a: &[T]) -> T {
let mut largest = a[0];
for &i in a.iter() {
if i < largest {
largest = i;
}
}
largest
}
但是即使這樣編譯器還是會報錯,這是因為
使用了largest這個變數,將 a 陣列中的值指派給了其他變數,所以也必須實現
Copy 那添加方式則是在 PartialOrd 寫個 + 號後面再加 Copy。
最後的程式會像這樣
pub fn Tfunc<T: PartialOrd + Copy>(a: &[T]) -> T {
let mut largest = a[0];
for &i in a.iter() {
if i < largest {
largest = i;
}
}
largest
}
這樣就編譯成功了!
那其實呼叫的方式就是直接讓它判斷傳入的值是什麼。
Ex:
pub fn Tcall() {
let int_list = vec![34, 50, 25, 100, 65];
function::Tfunc(&int_list);
}
或者說,也能使用 turbofish 的語法,讓編譯器可以先判斷是什麼型別,
不過即使使用了 turbofish 還是要在 T 上加 PartialOrd 跟 Copy 的特性
Ex:
pub fn Tcall() {
let int_list = vec![34, 50, 25, 100, 65];
function::Tfunc::<i32>(&int_list);
}
那可能你也會想說,一定要用 T 嗎?
答案是,其實不用。
而這也代表了,泛型不只能使用一種型別的變數。
也就是可以定義一個 T 是 i32 一個 W 是 i64
今天的內容可能有些難澀,我自己也不常使用。
但是蠻有趣和好玩的,學起來總是有會用到的時候。
明天我想講一些簡單的閉包和基礎的運算 if else match
有問題可以直接提問喔 owob然後小小抱怨一下,我早上存的草稿竟然不見了 QQQQQ 幸好發現的早 不然就沒有後續ㄌ